package mware_lib;

//To save the skeletons used in a DB, to create and save new Skeletons, to remove of the DB and to give back a skeleton to a service, so it can have access to the methods
//(like createAccount for a Manager)

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;

import mware_lib.communication.ProxyMess;


public class SkControl {
	
	public static final int skPort = 2554;
	public static Hashtable<String, Skeleton<?>> skDataBase=new Hashtable<String, Skeleton<?>>();
	
	public SkControl()
	{
		if(skDataBase == null)
			skDataBase = new Hashtable<String, Skeleton<?>>();
	}
	
	private static SocketConnection waitConnection = new SocketConnection(); //wait for a connection
	
	public static void newSkeleton(String name, Object object)
	{
		Class<?> toGet = null;
		Skeleton<?> sk = null;
		try {
			toGet = (Class<?>) (object.getClass().getSuperclass()).getMethod(
					"getSkeletonClass").invoke(null, (Object[]) null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (toGet == null)
		{
			System.err.println("mware_lib.SkControl: unknown Object");
			System.exit(1);
		}
		else
		{
			try{
				sk = (Skeleton<?>) toGet.getConstructor(
						object.getClass().getSuperclass()).newInstance(object);
			}catch(Throwable e)
			{
				//TODO: throw RemoteException
				System.err.println("mware_lib.SkControl: problem with creation of skeleton " + e.getMessage());
			}
			skDataBase.put(name, sk);
		}
	}
	
	public static void removeSkeleton(String name)
	{
		skDataBase.remove(name);
	}
}

class SocketConnection extends Thread {
	private ServerSocket servSocket=null;
	
	public SocketConnection()
	{
		this.setDaemon(true);
		this.start();
	}
	
	public void run()
	{
		boolean end=false;
		while(!end)
		{
			try {
				if(servSocket == null)
					servSocket = new ServerSocket(SkControl.skPort);
				WaitingConnection connection = new WaitingConnection(servSocket.accept());
				connection.start();
			} catch (IOException e) {
				System.err.println("Can't contact the skeleton: " + e + " " + e.getMessage());
				end=true;
			}
		}
	}
}

class WaitingConnection extends Thread {
	private Socket socketReceived;
	
	public WaitingConnection(Socket socketReceived)
	{
		this.socketReceived = socketReceived;
	}
	
	public void run(){
		Object oReceived = null;
		ObjectOutputStream out;
        ObjectInputStream in;
        Object result=null;
        try {
            in = new ObjectInputStream(socketReceived.getInputStream());
            out = new ObjectOutputStream(socketReceived.getOutputStream());
            oReceived = in.readObject();
            
            if(oReceived instanceof ProxyMess)
            {
            	ProxyMess mess = (ProxyMess) oReceived;
            	Skeleton<?> skeleton = SkControl.skDataBase.get(mess.id);
				if (skeleton == null) 
				{
					throw new RemoteException("Skeleton not found");
				} else 
				{
					try {
						result = skeleton.callMethod(mess.typeof,
								mess.args);
					} catch (Throwable e) {
						throw new RemoteException("Exception in SkControl: " + e.getMessage());
					}
				}
            }
            else
            {
            	throw new RemoteException("Unknown message received in SkControl");
            }
            
            out.writeObject(result);
            in.close();
            out.close();
            socketReceived.close();
             
        } catch (IOException e) {
             System.err.println("namensdienst.NSConnectionTreatment exception: " + e.getMessage());
        } catch (ClassNotFoundException e) {
             System.err.println("namensdienst.NSConnectionTreatment exception: " + e.getMessage());
        } catch (RemoteException e) {
			System.err.println(e.getMessage());
		}
	}
}
